package com.ruoyi.sms;

import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.sdk.sms.api.ISmsGateWayApi;
import com.ruoyi.common.sdk.sms.vo.request.SendMsgRequest;
import com.ruoyi.common.sdk.sms.vo.respone.SendMsgRespone;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.domain.TMessageRecord;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.system.service.ITMessageRecordService;
import io.jsonwebtoken.Claims;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * @author ruoyi
 */
@Slf4j
@RestController
@RequestMapping("/sms")
public class SmsController extends BaseController {

    @Autowired
    ISmsGateWayApi smsGateWayApi;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private ISysUserService sysUserService;
    @Autowired
    private ISysConfigService configService;
    @Autowired
    private ITMessageRecordService itMessageRecordService;

    //发送短信 校验是不是内部号码，1分钟（配置）只能发送一次短信，每天只能发送10次（配置）短信
    @ApiOperation(value = "短信验证码发送", notes = "短信验证码发送")
    @GetMapping("/sendMessage")
    public AjaxResult sendMessage(@RequestParam String phone) {
        SysUser sysUser = sysUserService.query().eq("phonenumber",phone).one();
        if (sysUser == null) {
            return AjaxResult.error("该手机号不是内部号码，无法使用！");
        }

        String messageCodeEffectiveTime = configService.selectConfigByKey(Constants.MESSAGE_CODE_EFFECTIVE_TIME);
        String messageCodeDayMaxCount = configService.selectConfigByKey(Constants.MESSAGE_CODE_DAY_MAX_COUNT);
        Integer effectiveTime = 5;
        Integer dayMaxCount = 10;
        try {
            effectiveTime = Integer.valueOf(messageCodeEffectiveTime);
            dayMaxCount = Integer.valueOf(messageCodeDayMaxCount);
        } catch (Exception e) {
            throw new NumberFormatException();
        }
        String messageCode = redisCache.getCacheObject(Constants.MESSAGE_CODE + phone);
        if (StringUtils.isNoneBlank(messageCode)) {
            return AjaxResult.error("该手机号" + effectiveTime + "分钟内已发送过短信验证码，请耐心等待！");
        }
        //是否超过一天最大限制
        Integer messageCodeCount = redisCache.getCacheObject(Constants.MESSAGE_CODE_COUNT + phone);
        if (messageCodeCount != null && !messageCodeCount.equals(0) && messageCodeCount >= dayMaxCount) {
            return AjaxResult.error("该手机号一天内发送短信验证码次数已达到上限，请明天再试！");
        }

        Random random = new Random();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 6; i++) {
            int digit = random.nextInt(10); // 生成0-9的随机数
            sb.append(digit);
        }
        redisCache.setCacheObject(Constants.MESSAGE_CODE + phone, sb, effectiveTime, TimeUnit.MINUTES);
        if (messageCodeCount == null || messageCodeCount.equals(0)) {
            redisCache.setCacheObject(Constants.MESSAGE_CODE_COUNT + phone, 1, 24, TimeUnit.HOURS);
        } else {
            redisCache.setCacheObject(Constants.MESSAGE_CODE_COUNT + phone, messageCodeCount + 1, 24, TimeUnit.HOURS);
        }
        //发送短信
        SendMsgRequest request = new SendMsgRequest("FWZYX", "d4aa95007d724af8b1803668bb9a6650");
        request.setMobilePhone(phone);
        String content = "【支局绑定】 你的验证码：" + sb + "，有效期为" + effectiveTime + "分钟，请妥善保管。";
        request.setContent(content);
        request.setTimestamp(String.valueOf(System.currentTimeMillis()));
        try {
            SendMsgRespone sendMsgRespone = smsGateWayApi.sendMsg(request);
            TMessageRecord messageRecord = new TMessageRecord();
            messageRecord.setMessage(content);
            messageRecord.setMessageRespone(sendMsgRespone.getText());
            messageRecord.setContactsPhone(phone);
            messageRecord.setCreateTime(LocalDateTime.now());
            itMessageRecordService.save(messageRecord);
        } catch (Exception e) {
            throw new RuntimeException();
        }
        return AjaxResult.success();
    }

    /**
     * 短信验证码登陆接口
     * 手机号是否内部用户，验证码是否正确
     * 登陆成功后，生成token，返回给前端
     */
    @GetMapping("/loginByMessageCode")
    public AjaxResult loginByMessageCode(@RequestParam String phone, @RequestParam String code) {
        if (StringUtils.isBlank(phone) || StringUtils.isBlank(code)) {
            return AjaxResult.error("手机号和验证码不能为空");
        }
        //丢入缓存
        Map<String, Object> map = new HashMap<>();
        try {
            SysUser sysUser = sysUserService.query().eq("phonenumber",phone).one();
            if (null == sysUser) {
                return AjaxResult.error("该手机号不是内部号码，无法使用！");
            }
            sysUser.setPassword(null);
            String messageCode = redisCache.getCacheObject(Constants.MESSAGE_CODE + phone);
            if (StringUtils.isBlank(messageCode)) {
                return AjaxResult.error("该验证码不正确或者已过期，请重新输入！");
            }
            if (!code.equals(messageCode)) {
                return AjaxResult.error("该验证码不正确或者已过期，请重新输入！");
            }
            String token = redisCache.getCacheObject(Constants.TOKEN_PHONE + phone);
            if (StringUtils.isNoneBlank(token)) {
                Claims claims = tokenService.parseToken(token);
                String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
                String userKey = tokenService.getTokenKey(uuid);
                LoginUser user = redisCache.getCacheObject(userKey);
                if (user != null) {
                    map.put("token", token);
                    map.put("sysUser", sysUser);
                    redisCache.deleteObject(Constants.MESSAGE_CODE + phone);
                    return AjaxResult.success(map);
                } else {
                    String newToken = appLogin(map, sysUser);
                    redisCache.setCacheObject(Constants.TOKEN_PHONE + phone, newToken, 12, TimeUnit.HOURS);
                    redisCache.deleteObject(Constants.MESSAGE_CODE + phone);
                }
            } else {
                String newToken = appLogin(map, sysUser);
                redisCache.setCacheObject(Constants.TOKEN_PHONE + phone, newToken, 30, TimeUnit.DAYS);
                redisCache.deleteObject(Constants.MESSAGE_CODE + phone);
            }

            return AjaxResult.success(map);
        } catch (Exception e) {
            this.logger.error(e.getMessage(), e);
        }
        return AjaxResult.success();
    }

    @GetMapping("/loginOut")
    public AjaxResult loginOut(HttpServletRequest request) {
        LoginUser loginUser = tokenService.getLoginUser(request);
        if (com.ruoyi.common.utils.StringUtils.isNotNull(loginUser)) {
            // 删除用户缓存记录
            tokenService.delLoginUser(loginUser.getToken());
        }
        return AjaxResult.success();
    }

    @GetMapping("/getUserInfo")
    public AjaxResult getUserInfo() {
        return AjaxResult.success(SecurityUtils.getLoginUser());
    }

    private String appLogin(Map<String, Object> result, SysUser sysUser) {
        LoginUser loginUser = new LoginUser();
        loginUser.setUserId(sysUser.getUserId());
        loginUser.setDeptId(sysUser.getDeptId());
        loginUser.setUser(sysUser);
        recordLoginInfo(loginUser.getUserId());
        String token = tokenService.createToken(loginUser);

        result.put("sysUser", sysUser);
        result.put("token", token);
        return token;
    }

    public void recordLoginInfo(Long userId) {
        SysUser sysUser = new SysUser();
        sysUser.setUserId(userId);
        sysUser.setLoginIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
        sysUser.setLoginDate(DateUtils.getNowDate());
        sysUserService.updateUserProfile(sysUser);
    }
    /**
     * <pre>
     * 发送短信
     * </pre>
     */
    @PostMapping("/sendSms")
    public AjaxResult sendSms(@RequestBody SendMsgRequest request) {
        try {
            /** 发送短信 */
            request.setTimestamp(String.valueOf(System.currentTimeMillis()));
            SendMsgRespone sendMsgRespone = smsGateWayApi.sendMsg(request);
            return AjaxResult.success(sendMsgRespone);
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error(e.getMessage());
        }
    }

}
